package net.binarism.journal
{
	import flash.desktop.DockIcon;
	import flash.desktop.NativeApplication;
	import flash.desktop.SystemTrayIcon;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.NativeMenu;
	import flash.display.NativeMenuItem;
	import flash.display.NativeWindowDisplayState;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.MouseEvent;
	import flash.events.NativeWindowDisplayStateEvent;
	import flash.net.URLRequest;
	
	import mx.controls.Alert;
	import mx.events.CloseEvent;
		
	public class DockManager extends EventDispatcher
	{
		private var dockImage:BitmapData;
		private var _stage:Stage;
		
		
		public function DockManager(stage:Stage)
		{
			_stage = stage;
			//Use the loader object to load an image, which will be used for the systray       //After the image has been loaded into the object, we can prepare the application       //for docking to the system tray 
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, prepareForSystray);
			loader.load(new URLRequest("icon.png"));
		}
		
		
		// Event handler function for displaying the selected Alert button. 
		private function alertCloseHandler(event:CloseEvent):void {
			if (event.detail==Alert.YES) {
				closeApp(event);
			} else {
				dock();
			}
		}
	
		
		public function prepareForSystray(event:Event):void {
			//Retrieve the image being used as the systray icon 
			dockImage = event.target.content.bitmapData;
			
			//For windows systems we can set the systray props       //(there's also an implementation for mac's, it's similar and you can find it on the net... ;) ) 
			if (NativeApplication.supportsSystemTrayIcon){
				setSystemTrayProperties();
				
				//Set some systray menu options, so that the user can right-click and access functionality          //without needing to open the application          
				SystemTrayIcon(NativeApplication.nativeApplication .icon).menu = createSystrayRootMenu();
			}
			else if (NativeApplication.supportsDockIcon){
				setDockProperties();
				DockIcon(NativeApplication.nativeApplication.icon).menu = createSystrayRootMenu();
			}
			
			if(NativeApplication.supportsMenu){
				NativeApplication.nativeApplication.menu = createOsxRootMenu();
			}
			
			//Setting the bitmaps array will show the application icon in the systray 
			NativeApplication.nativeApplication .icon.bitmaps = [dockImage];
		}
		
		
		private function createSystrayRootMenu():NativeMenu{
			//Add the menuitems with the corresponding actions 
			var menu:NativeMenu = new NativeMenu();
			var openNativeMenuItem:NativeMenuItem = new NativeMenuItem("Show journal");
			var setJournalLocationNativeMenuItem:NativeMenuItem = new NativeMenuItem("Set journal location");
			var exitNativeMenuItem:NativeMenuItem = new NativeMenuItem("Exit");
			
			//What should happen when the user clicks on something...       
			openNativeMenuItem.addEventListener(Event.SELECT, undock);
			setJournalLocationNativeMenuItem.addEventListener(Event.SELECT, setJournalLocation);
			exitNativeMenuItem.addEventListener(Event.SELECT, closeApp);
			
			//Add the menuitems to the menu 
			menu.addItem(openNativeMenuItem);
			menu.addItem(setJournalLocationNativeMenuItem);
			menu.addItem(new NativeMenuItem("",true));
			//separator 
			menu.addItem(exitNativeMenuItem);
			
			return menu;
		}
		
		
		private function createOsxRootMenu():NativeMenu{
			//Add the menuitems with the corresponding actions 
			var menu:NativeMenu = NativeApplication.nativeApplication.menu;
			var openNativeMenuItem:NativeMenuItem = new NativeMenuItem("Show journal");
			var showNativeMenuItem:NativeMenuItem = new NativeMenuItem("Show journal");
			var setJournalLocationNativeMenuItem:NativeMenuItem = new NativeMenuItem("Set journal location");
			var exitNativeMenuItem:NativeMenuItem = new NativeMenuItem("Exit");
			
			//What should happen when the user clicks on something...       
			openNativeMenuItem.addEventListener(Event.SELECT, undock);
			openNativeMenuItem.keyEquivalent = "1";
			showNativeMenuItem.addEventListener(Event.SELECT, undock);
			showNativeMenuItem.keyEquivalent = "1";
			setJournalLocationNativeMenuItem.addEventListener(Event.SELECT, setJournalLocation);
			exitNativeMenuItem.addEventListener(Event.SELECT, closeApp);
			
			//Add the menuitems to the menu 
			(menu.getItemAt(1).submenu).addItem(new NativeMenuItem("",true)); 
			(menu.getItemAt(1).submenu).addItem(openNativeMenuItem);
			(menu.getItemAt(1).submenu).addItem(setJournalLocationNativeMenuItem);
			(menu.getItemAt(1).submenu).addItem(new NativeMenuItem("",true)); 
			(menu.getItemAt(1).submenu).addItem(exitNativeMenuItem);
			
			(menu.getItemAt(3).submenu).addItem(new NativeMenuItem("",true));
			(menu.getItemAt(3).submenu).addItem(showNativeMenuItem);
			
			return menu;
		}
		
		
		/**
		 * To be able to dock and undock we need to set some eventlisteners
		 *
		 * @Author: S.Radovanovic
		 */
		private function setSystemTrayProperties():void{
			//Text to show when hovering of the docked application icon       
			SystemTrayIcon(NativeApplication.nativeApplication .icon).tooltip = "Journal";
			
			//We want to be able to open the application after it has been docked       
			SystemTrayIcon(NativeApplication.nativeApplication .icon).addEventListener(MouseEvent.CLICK, undock);
			
			//Listen to the display state changing of the window, so that we can catch the minimize       
			_stage.nativeWindow.addEventListener(NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGING, nwMinimized); //Catch the minimize event 
		}
		
		
		private function setDockProperties():void{
//			DockIcon(NativeApplication.nativeApplication.icon).tooltip = "Journal";
			DockIcon(NativeApplication.nativeApplication.icon).addEventListener(MouseEvent.CLICK, undock);
			
			_stage.nativeWindow.addEventListener(NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGING, nwMinimized);
		}
		
		
		/**
		 * Do the appropriate actions after the windows display state has changed.
		 * E.g. dock when the user clicks on minize
		 *
		 * @Author: S.Radovanovic
		 */
		private function nwMinimized(displayStateEvent:NativeWindowDisplayStateEvent):void {
			
			//Do we have an minimize action?       //The afterDisplayState hasn't happened yet, but only describes the state the window will go to,       //so we can prevent it! 
			if(displayStateEvent.afterDisplayState == NativeWindowDisplayState.MINIMIZED) {
				//Prevent the windowedapplication minimize action from happening and implement our own minimize          //The reason the windowedapplication minimize action is caught, is that if active we're not able to          //undock the application back neatly. The application doesn't become visible directly, but only after clicking          //on the taskbars application link. (Not sure yet what happens exactly with standard minimize) 
				displayStateEvent.preventDefault();
				
				//Dock (our own minimize) 
				dock();
			}
		}
		
		
		/**
		 * Do our own 'minimize' by docking the application to the systray (showing the application icon in the systray)
		 *
		 * @Author: S.Radovanovic
		 */
		public function dock():void {
			//Hide the applcation 
			_stage.nativeWindow.visible = false;
			
			//Setting the bitmaps array will show the application icon in the systray 
			NativeApplication.nativeApplication .icon.bitmaps = [dockImage];
		}
		
		
		/**
		 * Show the application again and remove the application icon from the systray
		 *
		 * @Author: S.Radovanovic
		 */
		public function undock(evt:Event):void {
			//After setting the window to visible, make sure that the application is ordered to the front,       //else we'll still need to click on the application on the taskbar to make it visible 
			_stage.nativeWindow.visible = true;
			_stage.nativeWindow.orderToFront();
			
		}
		
		
		private function setJournalLocation(evt:Event = null):void{
			//TOOD fire set location action
			var event:DockEvent = new DockEvent(DockEvent.SET_LOCATION_MENU_ITEM_FIRED);
			this.dispatchEvent(event);
		}
		
		
		/**
		 * Close the application
		 *
		 * @Author: S.Radovanovic
		 */
		private function closeApp(evt:Event):void {
			_stage.nativeWindow.close();
		}
	}
}